<html>
<head>
<link rel="shortcut icon" href="./favicon.ico">
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="canonical" href="./Pipeline_Half_Buffer.html">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="A single pipeline register with ready/valid handshakes.  Decouples the input and ouput handshakes (no combinational path), but does not allow concurrent read/write like a full [Pipeline Skid Buffer](./Pipeline_Skid_Buffer.html). The Half-Buffer must be read out before you can write into it again, halving the maximum bandwidth (except in Circular Buffer Mode).">
<title>Pipeline Half Buffer</title>
</head>
<body>

<p class="inline bordered"><b><a href="./Pipeline_Half_Buffer.v">Source</a></b></p>
<p class="inline bordered"><b><a href="./legal.html">License</a></b></p>
<p class="inline bordered"><b><a href="./index.html">Index</a></b></p>

<h1>Pipeline Half-Buffer</h1>
<p>A single pipeline register with ready/valid handshakes.  Decouples the
 input and ouput handshakes (no combinational path), but does not allow
 concurrent read/write like a full <a href="./Pipeline_Skid_Buffer.html">Pipeline Skid Buffer</a>.
 The Half-Buffer must be read out before you
 can write into it again, halving the maximum bandwidth (except in Circular
 Buffer Mode).</p>
<p>However, using a Half-Buffer can improve the throughput of a long-running
 module with ready/valid handshakes, where the module input will not accept
 new data until the module output is read out, and it takes multiple cycles
 to compute a result. With a Half-Buffer, the module can immediately dump
 its output into the Half-Buffer and then accept new input data, overlapping
 another computation with the wait time until the final destination reads
 out the Half-Buffer.</p>
<p>A Half-Buffer can also implement a very useful control mechanism by
 signalling to the source when the next item can be processed.  After
 accepting an item at the input, detecting the rise of valid at the output
 with a <a href="./Pulse_Generator.html">Pulse Generator</a> starts the internal logic,
 whose control logic now only need to pulse ready when the calculation is
 done to complete the handshake. This simplifies control and maintains
 concurrency.</p>
<h2>Circular Buffer Mode</h2>
<p>Normally, a Half-Buffer reads in one value and will not complete another
 input handshake until the data has been read out. You can think of this as
 buffering the <em>earliest</em> value from the pipeline.</p>
<p>Setting <code>CIRCULAR_BUFFER</code> parameter to a non-zero value changes the
 behaviour at the input: the input handshake can always complete, discarding
 the data already in the buffer even if it was never read out.  You can
 think of this as buffering the <em>latest</em> value from the pipeline.  This is
 a one-entry circular buffer.</p>
<p>However, data in the buffer can only be read out <em>once</em>, as usual, until
 updated again at the input, possibly in the same clock cycle. Simultaneous
 input and output handshakes are possible in Circular Buffer Mode since
 <code>input_ready</code> no longer depends on the empty/full state of the buffer
 (which forces alternation of input and output handshakes), nor on the state
 of the output handshake (which is disallowed to prevent creating
 a combinational path between input and output).</p>

<pre>
`default_nettype none

module <a href="./Pipeline_Half_Buffer.html">Pipeline_Half_Buffer</a>
#(
    parameter WORD_WIDTH            = 0,
    parameter CIRCULAR_BUFFER       = 0     // non-zero to enable
)
(
    input  wire                     clock,
    input  wire                     clear,

    input  wire                     input_valid,
    output reg                      input_ready,
    input  wire [WORD_WIDTH-1:0]    input_data,

    output reg                      output_valid,
    input  wire                     output_ready,
    output wire [WORD_WIDTH-1:0]    output_data
);

    localparam WORD_ZERO = {WORD_WIDTH{1'b0}};
</pre>

<p>Storage for the data</p>

<pre>
    reg half_buffer_load = 1'b0;

    <a href="./Register.html">Register</a>
    #(
        .WORD_WIDTH     (WORD_WIDTH),
        .RESET_VALUE    (WORD_ZERO)
    )
    half_buffer
    (
        .clock          (clock),
        .clock_enable   (half_buffer_load),
        .clear          (clear),
        .data_in        (input_data),
        .data_out       (output_data)
    );
</pre>

<p>And an empty/full bit associated with the data storage.</p>

<pre>
    reg  set_to_empty = 1'b0;
    reg  set_to_full  = 1'b0;
    wire buffer_full;

    <a href="./Register.html">Register</a>
    #(
        .WORD_WIDTH     (1),
        .RESET_VALUE    (1'b0)
    )
    empty_full
    (
        .clock          (clock),
        .clock_enable   (set_to_full),
        .clear          (set_to_empty),
        .data_in        (1'b1),
        .data_out       (buffer_full)
    );
</pre>

<p>Then, from the state of the empty/full bit and the signals local only to
 each handshake (no path between them), determine when data can transfer.
 Note that we must be empty before we can <code>set_to_full</code>. Anything else
 creates a combinational path from the input handshake to the output
 handshake.</p>
<p>EXCEPTION: In Circular Buffer Mode, <code>input_ready</code> does not depend on any
 other logic, which enables simultaneous input and output handhsakes without
 combinational paths between them.</p>

<pre>
    always @(*) begin
        input_ready      = (buffer_full   == 1'b0) || (CIRCULAR_BUFFER != 0);
        output_valid     = (buffer_full   == 1'b1);
        set_to_full      = (input_valid   == 1'b1) && (input_ready  == 1'b1);
        set_to_empty     = (output_valid  == 1'b1) && (output_ready == 1'b1) && (set_to_full == 1'b0);
        set_to_empty     = (set_to_empty  == 1'b1) || (clear == 1'b1);
        half_buffer_load = (set_to_full   == 1'b1);
    end

endmodule
</pre>

<hr>
<p><a href="./index.html">Back to FPGA Design Elements</a>
<center><a href="https://fpgacpu.ca/">fpgacpu.ca</a></center>
</body>
</html>

